using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows.Media;
using Meebey.SmartIrc4net;
using Thunder.IrcClient.MessageParser.Default;
using System.Windows;

namespace Thunder.IrcClient.MessageParser
{
    public delegate void ChannelHandler(string channel);
    public delegate void WriteTextHandler(string channel, string text, Color color, FontWeight weight, FontStyle style);
    public delegate void MemberHandler(string channel, string name);

    /// <summary>
    /// Manager for <see cref="IrcMessageData"/> messages
    /// </summary>
    public sealed class MessageManager
    {
        private readonly Dictionary<ReceiveType, List<IMessageParser>> customParsers = new Dictionary<ReceiveType, List<IMessageParser>>();
        private readonly Dictionary<ReceiveType, List<IMessageParser>> defaultParsers = new Dictionary<ReceiveType, List<IMessageParser>>();

        public ChannelHandler AddChannel;
        public ChannelHandler OpenChannel;
        public ChannelHandler CloseChannel;
        public WriteTextHandler WriteText;
        public MemberHandler AddMember;
        public MemberHandler RemoveMember;

        /// <summary>
        /// Gets the current <see cref="IrcClient"/> instance
        /// </summary>
        public Meebey.SmartIrc4net.IrcClient IrcClient { get; private set; }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="client">The current <see cref="IrcClient"/> instance</param>
        internal MessageManager(Meebey.SmartIrc4net.IrcClient client)
        {
            this.IrcClient = client;

            this.LoadCustomParsers();
            this.LoadDefaultParsers();
        }

        /// <summary>
        /// Loads the list of default <see cref="IMessageParser"/>'s
        /// </summary>
        private void LoadDefaultParsers()
        {
            this.defaultParsers.Add(ReceiveType.List, new List<IMessageParser>());
            this.defaultParsers.Add(ReceiveType.Join, new List<IMessageParser>());
            this.defaultParsers.Add(ReceiveType.Part, new List<IMessageParser>());
            this.defaultParsers.Add(ReceiveType.Motd, new List<IMessageParser>());
            this.defaultParsers.Add(ReceiveType.Unknown, new List<IMessageParser>());
            this.defaultParsers.Add(ReceiveType.Info, new List<IMessageParser>());
            this.defaultParsers.Add(ReceiveType.Login, new List<IMessageParser>());
            this.defaultParsers.Add(ReceiveType.CtcpRequest, new List<IMessageParser>());
            this.defaultParsers.Add(ReceiveType.Name, new List<IMessageParser>());
            this.defaultParsers.Add(ReceiveType.ChannelMessage, new List<IMessageParser>());

            this.defaultParsers.Add(ReceiveType.Error, new List<IMessageParser>());
            this.defaultParsers.Add(ReceiveType.ErrorMessage, new List<IMessageParser>());

            IMessageParser parser = new MessageParserJoin();
            parser.Initialize(this);
            this.defaultParsers[ReceiveType.Join].Add(parser);

            parser = new MessageParserList();
            parser.Initialize(this);
            this.defaultParsers[ReceiveType.List].Add(parser);

            parser = new MessageParserMOTD();
            parser.Initialize(this);
            this.defaultParsers[ReceiveType.Motd].Add(parser);

            parser = new MessageParserDefault();
            parser.Initialize(this);
            this.defaultParsers[ReceiveType.Unknown].Add(parser);

            parser = new MessageParserError();
            parser.Initialize(this);
            this.defaultParsers[ReceiveType.Error].Add(parser);

            parser = new MessageParserError();
            parser.Initialize(this);
            this.defaultParsers[ReceiveType.ErrorMessage].Add(parser);

            parser = new MessageParserDefault();
            parser.Initialize(this);
            this.defaultParsers[ReceiveType.Info].Add(parser);

            parser = new MessageParserDefault();
            parser.Initialize(this);
            this.defaultParsers[ReceiveType.Login].Add(parser);

            parser = new MessageParserCtcpRequest();
            parser.Initialize(this);
            this.defaultParsers[ReceiveType.CtcpRequest].Add(parser);

            parser = new MessageParserPart();
            parser.Initialize(this);
            this.defaultParsers[ReceiveType.Part].Add(parser);

            parser = new MessageParserName();
            parser.Initialize(this);
            this.defaultParsers[ReceiveType.Name].Add(parser);

            parser = new MessageParserChannelMessage();
            parser.Initialize(this);
            this.defaultParsers[ReceiveType.ChannelMessage].Add(parser);
        }

        /// <summary>
        /// Loads the custom <see cref="IMessageParser"/>'s for the parser directory
        /// </summary>
        private void LoadCustomParsers()
        {
            
        }

        /// <summary>
        /// Parses the <see cref="IrcMessageData"/> using either default or custom message parsers
        /// </summary>
        /// <param name="data">The <see cref="IrcMessageData"/> to be parsed</param>
        public void ParseMessage(IrcMessageData data)
        {
            CancelMessageProcessingEventArgs args = new CancelMessageProcessingEventArgs(data);
            if (this.customParsers.ContainsKey(data.Type) == true)
            {
                foreach (IMessageParser customParser in customParsers[data.Type])
                {
                    customParser.Parse(args);
                    if (args.Cancel == true)
                    {
                        break;
                    }
                }
            }

            if (args.Cancel == true)
            {
                return;
            }

            if (this.defaultParsers.ContainsKey(data.Type) == true)
            {
                foreach (IMessageParser defaultParser in defaultParsers[data.Type])
                {
                    defaultParser.Parse(args);
                }
            }
            else
            {
                this.WriteStatus(string.Format(Localized.ParserTypeNotFound, data.Type, data.Message), Colors.Red);
            }
        }

        /// <summary>
        /// Writes a string to the status page using the specified <paramref name="color"/>
        /// </summary>
        /// <param name="message">The message to write</param>
        /// <param name="color">The <see cref="Color"/> to use</param>
        public void WriteStatus(string message, Color color)
        {
            this.WriteText(string.Empty, message, color, FontWeights.Bold, FontStyles.Normal);
        }

        /// <summary>
        /// Registers a <see cref="IMessageParser"/> for a specific <see cref="ReceiveType"/>
        /// </summary>
        /// <param name="type">The <see cref="ReceiveType"/> to register the parser for</param>
        /// <param name="parser">The <see cref="IMessageParser"/> to register</param>
        /// <exception cref="ArgumentOutOfRangeException">If the <paramref name="parser"/> has already been registered for the <paramref name="type"/> type</exception>
        /// <exception cref="ArgumentNullException">If <paramref name="parser"/> is null</exception>
        public void RegisterMessageParser(ReceiveType type, IMessageParser parser)
        {
            if (parser == null)
            {
                throw new ArgumentNullException("parser");
            }

            if (this.customParsers.ContainsKey(type) == false)
            {
                this.customParsers.Add(type, new List<IMessageParser>());
            }

            if (this.customParsers[type].Contains(parser) == true)
            {
                throw new ArgumentOutOfRangeException("parser", string.Format(CultureInfo.InvariantCulture, "The parser is already registered for the '{0}' type", type));
            }

            this.customParsers[type].Add(parser);
        }
    }
}